home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright (c) 1988, 1990 Regents of the University of California.
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms are permitted provided
- * that: (1) source distributions retain this entire copyright notice and
- * comment, and (2) distributions including binaries display the following
- * acknowledgement: ``This product includes software developed by the
- * University of California, Berkeley and its contributors'' in the
- * documentation or other materials provided with the distribution and in
- * all advertising materials mentioning features or use of this software.
- * Neither the name of the University nor the names of its contributors may
- * be used to endorse or promote products derived from this software without
- * specific prior written permission.
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- */
-
- #ifndef lint
- static char sccsid[] = "@(#)telnet.c 5.51 (Berkeley) 9/14/90";
- #endif /* not lint */
-
- #include <sys/types.h>
- #include <dos/dos.h>
-
- #ifdef KERBEROS
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <kerberosIV/des.h>
- #include <kerberosIV/krb.h>
- #include "krb4-proto.h"
- #endif
-
- #include <arpa/telnet.h>
-
- #include <string.h>
-
- #include <ctype.h>
-
- #include "ring.h"
-
- #include "defines.h"
- #include "externs.h"
- #include "types.h"
- #include "general.h"
-
- #define strip(x) ((x)&0x7f)
-
- extern char *env_getvalue();
-
- static char subbuffer[SUBBUFSIZE],
- *subpointer, *subend; /* buffer for sub-options */
- #define SB_CLEAR() subpointer = subbuffer;
- #define SB_TERM() subend = subpointer;
- #define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof subbuffer)) { \
- *subpointer++ = (c); \
- }
-
- char options[256]; /* The combined options */
- char do_dont_resp[256];
- char will_wont_resp[256];
-
- int
- connected,
- showoptions,
- ISend, /* trying to send network data in */
- debug = 0,
- crmod,
- netdata, /* Print out network data flow */
- crlf, /* Should '\r' be mapped to <CR><LF> (or <CR><NUL>)? */
- telnetport,
- SYNCHing, /* we are in TELNET SYNCH mode */
- flushout, /* flush output */
- autoflush = 0, /* flush output when interrupting? */
- autosynch, /* send interrupt characters with SYNCH? */
- localflow, /* we handle flow control locally */
- localchars, /* we recognize interrupt/quit */
- donelclchars, /* the user has set "localchars" */
- donebinarytoggle, /* the user has put us in binary */
- dontlecho, /* do we suppress local echoing right now? */
- globalmode;
-
- char *prompt = 0;
-
- cc_t escape;
-
- /*
- * Telnet receiver states for fsm
- */
- #define TS_DATA 0
- #define TS_IAC 1
- #define TS_WILL 2
- #define TS_WONT 3
- #define TS_DO 4
- #define TS_DONT 5
- #define TS_CR 6
- #define TS_SB 7 /* sub-option collection */
- #define TS_SE 8 /* looking for sub-option end */
-
- static int telrcv_state;
-
- jmp_buf toplevel = { 0 };
- jmp_buf peerdied;
-
- int flushline;
- int linemode;
-
- /*
- * The following are some clocks used to decide how to interpret
- * the relationship between various variables.
- */
-
- Clocks clocks;
-
- /*
- * Initialize telnet environment.
- */
-
- init_telnet()
- {
- env_init();
-
- SB_CLEAR();
- ClearArray(options);
-
- connected = ISend = localflow = donebinarytoggle = 0;
-
- SYNCHing = 0;
-
- /* Don't change NetTrace */
-
- escape = CONTROL(']');
- flushline = 1;
- telrcv_state = TS_DATA;
- }
-
-
-
- /*
- * These routines are in charge of sending option negotiations
- * to the other side.
- *
- * The basic idea is that we send the negotiation if either side
- * is in disagreement as to what the current state should be.
- */
-
- send_do(c, init)
- register int c, init;
- {
- if (init) {
- if (((do_dont_resp[c] == 0) && my_state_is_do(c)) ||
- my_want_state_is_do(c))
- return;
- set_my_want_state_do(c);
- do_dont_resp[c]++;
- }
- NET2ADD(IAC, DO);
- NETADD(c);
- printoption("SENT", "do", c);
- }
-
- void
- send_dont(c, init)
- register int c, init;
- {
- if (init) {
- if (((do_dont_resp[c] == 0) && my_state_is_dont(c)) ||
- my_want_state_is_dont(c))
- return;
- set_my_want_state_dont(c);
- do_dont_resp[c]++;
- }
- NET2ADD(IAC, DONT);
- NETADD(c);
- printoption("SENT", "dont", c);
- }
-
- void
- send_will(c, init)
- register int c, init;
- {
- if (init) {
- if (((will_wont_resp[c] == 0) && my_state_is_will(c)) ||
- my_want_state_is_will(c))
- return;
- set_my_want_state_will(c);
- will_wont_resp[c]++;
- }
- NET2ADD(IAC, WILL);
- NETADD(c);
- printoption("SENT", "will", c);
- }
-
- void
- send_wont(c, init)
- register int c, init;
- {
- if (init) {
- if (((will_wont_resp[c] == 0) && my_state_is_wont(c)) ||
- my_want_state_is_wont(c))
- return;
- set_my_want_state_wont(c);
- will_wont_resp[c]++;
- }
- NET2ADD(IAC, WONT);
- NETADD(c);
- printoption("SENT", "wont", c);
- }
-
-
- void
- willoption(option)
- int option;
- {
- int new_state_ok = 0;
-
- if (do_dont_resp[option]) {
- --do_dont_resp[option];
- if (do_dont_resp[option] && my_state_is_do(option))
- --do_dont_resp[option];
- }
-
- if ((do_dont_resp[option] == 0) && my_want_state_is_dont(option)) {
-
- switch (option) {
-
- case TELOPT_ECHO:
- case TELOPT_BINARY:
- case TELOPT_SGA:
- settimer(modenegotiated);
- /* FALL THROUGH */
- case TELOPT_STATUS:
- new_state_ok = 1;
- break;
-
- case TELOPT_TM:
- if (flushout)
- flushout = 0;
- /*
- * Special case for TM. If we get back a WILL,
- * pretend we got back a WONT.
- */
- set_my_want_state_dont(option);
- set_my_state_dont(option);
- return; /* Never reply to TM will's/wont's */
-
- case TELOPT_LINEMODE:
- default:
- break;
- }
-
- if (new_state_ok) {
- set_my_want_state_do(option);
- send_do(option, 0);
- setconnmode(0); /* possibly set new tty mode */
- } else {
- do_dont_resp[option]++;
- send_dont(option, 0);
- }
- }
- set_my_state_do(option);
- }
-
- void
- wontoption(option)
- int option;
- {
- if (do_dont_resp[option]) {
- --do_dont_resp[option];
- if (do_dont_resp[option] && my_state_is_dont(option))
- --do_dont_resp[option];
- }
-
- if ((do_dont_resp[option] == 0) && my_want_state_is_do(option)) {
-
- switch (option) {
-
- case TELOPT_ECHO:
- settimer(modenegotiated);
- break;
-
- case TELOPT_TM:
- if (flushout)
- flushout = 0;
- set_my_want_state_dont(option);
- set_my_state_dont(option);
- return; /* Never reply to TM will's/wont's */
-
- default:
- break;
- }
- set_my_want_state_dont(option);
- if (my_state_is_do(option))
- send_dont(option, 0);
- setconnmode(0); /* Set new tty mode */
- } else if (option == TELOPT_TM) {
- /*
- * Special case for TM.
- */
- if (flushout)
- flushout = 0;
- set_my_want_state_dont(option);
- }
- set_my_state_dont(option);
- }
-
- static void
- dooption(option)
- int option;
- {
- int new_state_ok = 0;
-
- if (will_wont_resp[option]) {
- --will_wont_resp[option];
- if (will_wont_resp[option] && my_state_is_will(option))
- --will_wont_resp[option];
- }
-
- if (will_wont_resp[option] == 0) {
- if (my_want_state_is_wont(option)) {
-
- switch (option) {
-
- case TELOPT_TM:
- /*
- * Special case for TM. We send a WILL, but pretend
- * we sent WONT.
- */
- send_will(option, 0);
- set_my_want_state_wont(TELOPT_TM);
- set_my_state_wont(TELOPT_TM);
- return;
-
- case TELOPT_BINARY: /* binary mode */
- case TELOPT_NAWS: /* window size */
- case TELOPT_TSPEED: /* terminal speed */
- case TELOPT_LFLOW: /* local flow control */
- case TELOPT_TTYPE: /* terminal type option */
- case TELOPT_SGA: /* no big deal */
- case TELOPT_ENVIRON: /* environment variable option */
- new_state_ok = 1;
- break;
-
- case TELOPT_XDISPLOC: /* X Display location */
- if (env_getvalue("DISPLAY"))
- new_state_ok = 1;
- break;
-
- case TELOPT_LINEMODE:
- set_my_want_state_will(TELOPT_LINEMODE);
- send_will(option, 0);
- set_my_state_will(TELOPT_LINEMODE);
- slc_init();
- return;
-
- case TELOPT_ECHO: /* We're never going to echo... */
- default:
- break;
- }
-
- if (new_state_ok) {
- set_my_want_state_will(option);
- send_will(option, 0);
- setconnmode(0); /* Set new tty mode */
- } else {
- will_wont_resp[option]++;
- send_wont(option, 0);
- }
- } else {
- /*
- * Handle options that need more things done after the
- * other side has acknowledged the option.
- */
- switch (option) {
- case TELOPT_LINEMODE:
- set_my_state_will(option);
- slc_init();
- send_do(TELOPT_SGA, 0);
- return;
- }
- }
- }
- set_my_state_will(option);
- }
-
- static void
- dontoption(option)
- int option;
- {
-
- if (will_wont_resp[option]) {
- --will_wont_resp[option];
- if (will_wont_resp[option] && my_state_is_wont(option))
- --will_wont_resp[option];
- }
-
- if ((will_wont_resp[option] == 0) && my_want_state_is_will(option)) {
- switch (option) {
- case TELOPT_LINEMODE:
- linemode = 0; /* put us back to the default state */
- break;
- }
- /* we always accept a DONT */
- set_my_want_state_wont(option);
- if (my_state_is_will(option))
- send_wont(option, 0);
- setconnmode(0); /* Set new tty mode */
- }
- set_my_state_wont(option);
- }
-
- /*
- * Given a buffer returned by tgetent(), this routine will turn
- * the pipe seperated list of names in the buffer into an array
- * of pointers to null terminated names. We toss out any bad,
- * duplicate, or verbose names (names with spaces).
- */
-
- static char *unknown[] = { "UNKNOWN", 0 };
-
- char **
- mklist(buf, name)
- char *buf, *name;
- {
- register int n;
- register char c, *cp, **argvp, *cp2, **argv;
- char *malloc();
-
- if (name) {
- if (strlen(name) > 40)
- name = 0;
- else {
- unknown[0] = name;
- upcase(name);
- }
- }
- /*
- * Count up the number of names.
- */
- for (n = 1, cp = buf; *cp && *cp != ':'; cp++) {
- if (*cp == '|')
- n++;
- }
- /*
- * Allocate an array to put the name pointers into
- */
- argv = (char **)malloc((n+3)*sizeof(char *));
- if (argv == 0)
- return(unknown);
-
- /*
- * Fill up the array of pointers to names.
- */
- *argv = 0;
- argvp = argv+1;
- n = 0;
- for (cp = cp2 = buf; (c = *cp); cp++) {
- if (c == '|' || c == ':') {
- *cp++ = '\0';
- /*
- * Skip entries that have spaces or are over 40
- * characters long. If this is our environment
- * name, then put it up front. Otherwise, as
- * long as this is not a duplicate name (case
- * insensitive) add it to the list.
- */
- if (n || (cp - cp2 > 41))
- ;
- else if (name && (strncasecmp(name, cp2, cp-cp2) == 0))
- *argv = cp2;
- else if (is_unique(cp2, argv+1, argvp))
- *argvp++ = cp2;
- if (c == ':')
- break;
- /*
- * Skip multiple delimiters. Reset cp2 to
- * the beginning of the next name. Reset n,
- * the flag for names with spaces.
- */
- while ((c = *cp) == '|')
- cp++;
- cp2 = cp;
- n = 0;
- }
- /*
- * Skip entries with spaces or non-ascii values.
- * Convert lower case letters to upper case.
- */
- if ((c == ' ') || !isascii(c))
- n = 1;
- else if (islower(c))
- *cp = toupper(c);
- }
-
- /*
- * Check for an old V6 2 character name. If the second
- * name points to the beginning of the buffer, and is
- * only 2 characters long, move it to the end of the array.
- */
- if ((argv[1] == buf) && (strlen(argv[1]) == 2)) {
- *argvp++ = buf;
- cp = *argv++;
- *argv = cp;
- }
-
- /*
- * Duplicate last name, for TTYPE option, and null
- * terminate the array. If we didn't find a match on
- * our terminal name, put that name at the beginning.
- */
- cp = *(argvp-1);
- *argvp++ = cp;
- *argvp = 0;
-
- if (*argv == 0) {
- if (name)
- *argv = name;
- else
- argv++;
- }
- if (*argv)
- return(argv);
- else
- return(unknown);
- }
-
- is_unique(name, as, ae)
- register char *name, **as, **ae;
- {
- register char **ap;
- register int n;
-
- n = strlen(name) + 1;
- for (ap = as; ap < ae; ap++)
- if (strncasecmp(*ap, name, n) == 0)
- return(0);
- return (1);
- }
-
- #ifdef TERMCAP
- char termbuf[1024];
- /*ARGSUSED*/
- setupterm(tname, fd, errp)
- char *tname;
- int fd, *errp;
- {
- #if 0
- if (tgetent(termbuf, tname) == 1) {
- termbuf[1023] = '\0';
- if (errp)
- *errp = 1;
- return(0);
- }
- #endif
- if (errp)
- *errp = 0;
- return(-1);
- }
- #else
- #define termbuf ttytype
- extern char ttytype[];
- #endif
-
- char *
- gettermname()
- {
- char *tname;
- static int first = 1;
- static char **tnamep;
- static char **next;
- int err;
-
- if (first) {
- first = 0;
- if ((tname = env_getvalue("TERM")) &&
- (setupterm(tname, 1, &err) == 0)) {
- tnamep = mklist(termbuf, tname);
- } else {
- if (tname && (strlen(tname) <= 40)) {
- unknown[0] = tname;
- upcase(tname);
- }
- tnamep = unknown;
- }
- next = tnamep;
- }
- if (*next == 0)
- next = tnamep;
- return(*next++);
- }
- /*
- * suboption()
- *
- * Look at the sub-option buffer, and try to be helpful to the other
- * side.
- *
- * Currently we recognize:
- *
- * Terminal type, send request.
- * Terminal speed (send request).
- * Local flow control (is request).
- * Linemode
- */
-
- static void
- suboption()
- {
- printsub('<', subbuffer, subend-subbuffer+2);
- switch (subbuffer[0]&0xff) {
- case TELOPT_TTYPE:
- if (my_want_state_is_wont(TELOPT_TTYPE))
- return;
- if ((subbuffer[1]&0xff) != TELQUAL_SEND) {
- ;
- } else {
- char *name;
- char temp[50];
- int len;
-
- name = gettermname();
- len = strlen(name) + 4 + 2;
- if (len < NETROOM()) {
- sprintf(temp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE,
- TELQUAL_IS, name, IAC, SE);
- ring_supply_data(&netoring, temp, len);
- printsub('>', &temp[2], len-2);
- } else {
- ExitString("No room in buffer for terminal type.\n", 1);
- /*NOTREACHED*/
- }
- }
- break;
- case TELOPT_TSPEED:
- if (my_want_state_is_wont(TELOPT_TSPEED))
- return;
- if ((subbuffer[1]&0xff) == TELQUAL_SEND) {
- long ospeed, ispeed;
- char temp[50];
- int len;
-
- #if defined(MCH_AMIGA) || defined(_AMIGA)
- ospeed = 9600;
- ispeed = 9600;
- #else
- TerminalSpeeds(&ispeed, &ospeed);
- #endif
- sprintf(temp, "%c%c%c%c%d,%d%c%c", IAC, SB, TELOPT_TSPEED,
- TELQUAL_IS, ospeed, ispeed, IAC, SE);
- len = strlen(temp+4) + 4; /* temp[3] is 0 ... */
-
- if (len < NETROOM()) {
- ring_supply_data(&netoring, temp, len);
- printsub('>', temp+2, len - 2);
- }
- /*@*/ else printf("lm_will: not enough room in buffer\n");
- }
- break;
- case TELOPT_LFLOW:
- if (my_want_state_is_wont(TELOPT_LFLOW))
- return;
- if ((subbuffer[1]&0xff) == 1) {
- localflow = 1;
- } else if ((subbuffer[1]&0xff) == 0) {
- localflow = 0;
- }
- setcommandmode();
- setconnmode(0);
- break;
-
- case TELOPT_LINEMODE:
- if (my_want_state_is_wont(TELOPT_LINEMODE))
- return;
- switch (subbuffer[1]&0xff) {
- case WILL:
- lm_will(&subbuffer[2], subend - &subbuffer[2]);
- break;
- case WONT:
- lm_wont(&subbuffer[2], subend - &subbuffer[2]);
- break;
- case DO:
- lm_do(&subbuffer[2], subend - &subbuffer[2]);
- break;
- case DONT:
- lm_dont(&subbuffer[2], subend - &subbuffer[2]);
- break;
- case LM_SLC:
- slc(&subbuffer[2], subend - &subbuffer[2]);
- break;
- case LM_MODE:
- lm_mode(&subbuffer[2], subend - &subbuffer[2], 0);
- break;
- default:
- break;
- }
- break;
-
- case TELOPT_ENVIRON:
- switch(subbuffer[1]&0xff) {
- case TELQUAL_IS:
- case TELQUAL_INFO:
- if (my_want_state_is_dont(TELOPT_ENVIRON))
- return;
- break;
- case TELQUAL_SEND:
- if (my_want_state_is_wont(TELOPT_ENVIRON)) {
- return;
- }
- break;
- default:
- return;
- }
- env_opt(&subbuffer[1], subend - &subbuffer[1]);
- break;
-
- case TELOPT_XDISPLOC:
- if (my_want_state_is_wont(TELOPT_XDISPLOC))
- return;
- if ((subbuffer[1]&0xff) == TELQUAL_SEND) {
- char temp[50], *dp;
- int len;
-
- if ((dp = env_getvalue("DISPLAY")) == NULL) {
- /*
- * Something happened, we no longer have a DISPLAY
- * variable. So, turn off the option.
- */
- send_wont(TELOPT_XDISPLOC, 1);
- break;
- }
- sprintf(temp, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_XDISPLOC,
- TELQUAL_IS, dp, IAC, SE);
- len = strlen(temp+4) + 4; /* temp[3] is 0 ... */
-
- if (len < NETROOM()) {
- ring_supply_data(&netoring, temp, len);
- printsub('>', temp+2, len - 2);
- }
- /*@*/ else printf("lm_will: not enough room in buffer\n");
- }
- break;
-
- default:
- break;
- }
- }
-
- static char str_lm[] = { IAC, SB, TELOPT_LINEMODE, 0, 0, IAC, SE };
-
- lm_will(cmd, len)
- unsigned char *cmd;
- {
- if (len < 1) {
- /*@*/ printf("lm_will: no command!!!\n"); /* Should not happen... */
- return;
- }
- switch(cmd[0]) {
- case LM_FORWARDMASK: /* We shouldn't ever get this... */
- default:
- str_lm[3] = DONT;
- str_lm[4] = cmd[0];
- if (NETROOM() > sizeof(str_lm)) {
- ring_supply_data(&netoring, str_lm, sizeof(str_lm));
- printsub('>', &str_lm[2], sizeof(str_lm)-2);
- }
- /*@*/ else printf("lm_will: not enough room in buffer\n");
- break;
- }
- }
-
- lm_wont(cmd, len)
- unsigned char *cmd;
- {
- if (len < 1) {
- /*@*/ printf("lm_wont: no command!!!\n"); /* Should not happen... */
- return;
- }
- switch(cmd[0]) {
- case LM_FORWARDMASK: /* We shouldn't ever get this... */
- default:
- /* We are always DONT, so don't respond */
- return;
- }
- }
-
- lm_do(cmd, len)
- unsigned char *cmd;
- {
- if (len < 1) {
- /*@*/ printf("lm_do: no command!!!\n"); /* Should not happen... */
- return;
- }
- switch(cmd[0]) {
- case LM_FORWARDMASK:
- default:
- str_lm[3] = WONT;
- str_lm[4] = cmd[0];
- if (NETROOM() > sizeof(str_lm)) {
- ring_supply_data(&netoring, str_lm, sizeof(str_lm));
- printsub('>', &str_lm[2], sizeof(str_lm)-2);
- }
- /*@*/ else printf("lm_do: not enough room in buffer\n");
- break;
- }
- }
-
- lm_dont(cmd, len)
- unsigned char *cmd;
- {
- if (len < 1) {
- /*@*/ printf("lm_dont: no command!!!\n"); /* Should not happen... */
- return;
- }
- switch(cmd[0]) {
- case LM_FORWARDMASK:
- default:
- /* we are always WONT, so don't respond */
- break;
- }
- }
-
- static char str_lm_mode[] = { IAC, SB, TELOPT_LINEMODE, LM_MODE, 0, IAC, SE };
-
- lm_mode(cmd, len, init)
- char *cmd;
- int len, init;
- {
- if (len != 1)
- return;
- if ((linemode&MODE_MASK&~MODE_ACK) == *cmd)
- return;
- if (*cmd&MODE_ACK)
- return;
- linemode = *cmd&(MODE_MASK&~MODE_ACK);
- str_lm_mode[4] = linemode;
- if (!init)
- str_lm_mode[4] |= MODE_ACK;
- if (NETROOM() > sizeof(str_lm_mode)) {
- ring_supply_data(&netoring, str_lm_mode, sizeof(str_lm_mode));
- printsub('>', &str_lm_mode[2], sizeof(str_lm_mode)-2);
- }
- /*@*/ else printf("lm_mode: not enough room in buffer\n");
- setconnmode(0); /* set changed mode */
- }
-
-
-
- /*
- * slc()
- * Handle special character suboption of LINEMODE.
- */
-
- struct spc {
- cc_t val;
- cc_t *valp;
- char flags; /* Current flags & level */
- char mylevel; /* Maximum level & flags */
- } spc_data[NSLC+1];
-
- #define SLC_IMPORT 0
- #define SLC_EXPORT 1
- #define SLC_RVALUE 2
- static int slc_mode = SLC_EXPORT;
-
- slc_init()
- {
- register struct spc *spcp;
- extern cc_t *tcval();
-
- localchars = 1;
- for (spcp = spc_data; spcp < &spc_data[NSLC+1]; spcp++) {
- spcp->val = 0;
- spcp->valp = 0;
- spcp->flags = spcp->mylevel = SLC_NOSUPPORT;
- }
-
- #define initfunc(func, flags) { \
- spcp = &spc_data[func]; \
- if (spcp->valp = tcval(func)) { \
- spcp->val = *spcp->valp; \
- spcp->mylevel = SLC_VARIABLE|flags; \
- } else { \
- spcp->val = 0; \
- spcp->mylevel = SLC_DEFAULT; \
- } \
- }
-
- initfunc(SLC_SYNCH, 0);
- /* No BRK */
- initfunc(SLC_AO, 0);
- initfunc(SLC_AYT, 0);
- /* No EOR */
- initfunc(SLC_ABORT, SLC_FLUSHIN|SLC_FLUSHOUT);
- initfunc(SLC_EOF, 0);
- initfunc(SLC_SUSP, SLC_FLUSHIN);
- initfunc(SLC_EC, 0);
- initfunc(SLC_EL, 0);
- initfunc(SLC_EW, 0);
- initfunc(SLC_RP, 0);
- initfunc(SLC_LNEXT, 0);
- initfunc(SLC_XON, 0);
- initfunc(SLC_XOFF, 0);
- initfunc(SLC_FORW1, 0);
-
- initfunc(SLC_IP, SLC_FLUSHIN|SLC_FLUSHOUT);
- #undef initfunc
-
- if (slc_mode == SLC_EXPORT)
- slc_export();
- else
- slc_import(1);
-
- }
-
- slcstate()
- {
- printf("Special characters are %s values\n",
- slc_mode == SLC_IMPORT ? "remote default" :
- slc_mode == SLC_EXPORT ? "local" :
- "remote");
- }
-
- slc_mode_export()
- {
- slc_mode = SLC_EXPORT;
- if (my_state_is_will(TELOPT_LINEMODE))
- slc_export();
- }
-
- slc_mode_import(def)
- {
- slc_mode = def ? SLC_IMPORT : SLC_RVALUE;
- if (my_state_is_will(TELOPT_LINEMODE))
- slc_import(def);
- }
-
- char slc_import_val[] = {
- IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_VARIABLE, 0, IAC, SE
- };
- char slc_import_def[] = {
- IAC, SB, TELOPT_LINEMODE, LM_SLC, 0, SLC_DEFAULT, 0, IAC, SE
- };
-
- slc_import(def)
- int def;
- {
- if (NETROOM() > sizeof(slc_import_val)) {
- if (def) {
- ring_supply_data(&netoring, slc_import_def, sizeof(slc_import_def));
- printsub('>', &slc_import_def[2], sizeof(slc_import_def)-2);
- } else {
- ring_supply_data(&netoring, slc_import_val, sizeof(slc_import_val));
- printsub('>', &slc_import_val[2], sizeof(slc_import_val)-2);
- }
- }
- /*@*/ else printf("slc_import: not enough room\n");
- }
-
- slc_export()
- {
- register struct spc *spcp;
-
- TerminalDefaultChars();
-
- slc_start_reply();
- for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
- if (spcp->mylevel != SLC_NOSUPPORT) {
- if (spcp->val == (cc_t)(_POSIX_VDISABLE))
- spcp->flags = SLC_NOSUPPORT;
- else
- spcp->flags = spcp->mylevel;
- if (spcp->valp)
- spcp->val = *spcp->valp;
- slc_add_reply(spcp - spc_data, spcp->flags, spcp->val);
- }
- }
- slc_end_reply();
- if (slc_update())
- setconnmode(1); /* set the new character values */
- }
-
- slc(cp, len)
- register char *cp;
- int len;
- {
- register struct spc *spcp;
- register int func,level;
-
- slc_start_reply();
-
- for (; len >= 3; len -=3, cp +=3) {
-
- func = cp[SLC_FUNC];
-
- if (func == 0) {
- /*
- * Client side: always ignore 0 function.
- */
- continue;
- }
- if (func > NSLC) {
- if ((cp[SLC_FLAGS] & SLC_LEVELBITS) != SLC_NOSUPPORT)
- slc_add_reply(func, SLC_NOSUPPORT, 0);
- continue;
- }
-
- spcp = &spc_data[func];
-
- level = cp[SLC_FLAGS]&(SLC_LEVELBITS|SLC_ACK);
-
- if ((cp[SLC_VALUE] == (unsigned char)spcp->val) &&
- ((level&SLC_LEVELBITS) == (spcp->flags&SLC_LEVELBITS))) {
- continue;
- }
-
- if (level == (SLC_DEFAULT|SLC_ACK)) {
- /*
- * This is an error condition, the SLC_ACK
- * bit should never be set for the SLC_DEFAULT
- * level. Our best guess to recover is to
- * ignore the SLC_ACK bit.
- */
- cp[SLC_FLAGS] &= ~SLC_ACK;
- }
-
- if (level == ((spcp->flags&SLC_LEVELBITS)|SLC_ACK)) {
- spcp->val = (cc_t)cp[SLC_VALUE];
- spcp->flags = cp[SLC_FLAGS]; /* include SLC_ACK */
- continue;
- }
-
- level &= ~SLC_ACK;
-
- if (level <= (spcp->mylevel&SLC_LEVELBITS)) {
- spcp->flags = cp[SLC_FLAGS]|SLC_ACK;
- spcp->val = (cc_t)cp[SLC_VALUE];
- }
- if (level == SLC_DEFAULT) {
- if ((spcp->mylevel&SLC_LEVELBITS) != SLC_DEFAULT)
- spcp->flags = spcp->mylevel;
- else
- spcp->flags = SLC_NOSUPPORT;
- }
- slc_add_reply(func, spcp->flags, spcp->val);
- }
- slc_end_reply();
- if (slc_update())
- setconnmode(1); /* set the new character values */
- }
-
- slc_check()
- {
- register struct spc *spcp;
-
- slc_start_reply();
- for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
- if (spcp->valp && spcp->val != *spcp->valp) {
- spcp->val = *spcp->valp;
- if (spcp->val == (cc_t)(_POSIX_VDISABLE))
- spcp->flags = SLC_NOSUPPORT;
- else
- spcp->flags = spcp->mylevel;
- slc_add_reply(spcp - spc_data, spcp->flags, spcp->val);
- }
- }
- slc_end_reply();
- setconnmode(1);
- }
-
-
- unsigned char slc_reply[128];
- unsigned char *slc_replyp;
- slc_start_reply()
- {
- slc_replyp = slc_reply;
- *slc_replyp++ = IAC;
- *slc_replyp++ = SB;
- *slc_replyp++ = TELOPT_LINEMODE;
- *slc_replyp++ = LM_SLC;
- }
-
- slc_add_reply(func, flags, value)
- char func;
- char flags;
- cc_t value;
- {
- if ((*slc_replyp++ = func) == IAC)
- *slc_replyp++ = IAC;
- if ((*slc_replyp++ = flags) == IAC)
- *slc_replyp++ = IAC;
- if ((*slc_replyp++ = (unsigned char)value) == IAC)
- *slc_replyp++ = IAC;
- }
-
- slc_end_reply()
- {
- register int len;
-
- *slc_replyp++ = IAC;
- *slc_replyp++ = SE;
- len = slc_replyp - slc_reply;
- if (len <= 6)
- return;
- if (NETROOM() > len) {
- ring_supply_data(&netoring, slc_reply, slc_replyp - slc_reply);
- printsub('>', &slc_reply[2], slc_replyp - slc_reply - 2);
- }
- /*@*/else printf("slc_end_reply: not enough room\n");
- }
-
- slc_update()
- {
- register struct spc *spcp;
- int need_update = 0;
-
- for (spcp = &spc_data[1]; spcp < &spc_data[NSLC+1]; spcp++) {
- if (!(spcp->flags&SLC_ACK))
- continue;
- spcp->flags &= ~SLC_ACK;
- if (spcp->valp && (*spcp->valp != spcp->val)) {
- *spcp->valp = spcp->val;
- need_update = 1;
- }
- }
- return(need_update);
- }
-
- env_opt(buf, len)
- register char *buf;
- register int len;
- {
- register char *ep = 0, *epc = 0;
- register int i;
-
- switch(buf[0]&0xff) {
- case TELQUAL_SEND:
- env_opt_start();
- if (len == 1) {
- env_opt_add(NULL);
- } else for (i = 1; i < len; i++) {
- switch (buf[i]&0xff) {
- case ENV_VALUE:
- if (ep) {
- *epc = 0;
- env_opt_add(ep);
- }
- ep = epc = &buf[i+1];
- break;
- case ENV_ESC:
- i++;
- /*FALL THROUGH*/
- default:
- if (epc)
- *epc++ = buf[i];
- break;
- }
- if (ep) {
- *epc = 0;
- env_opt_add(ep);
- }
- }
- env_opt_end(1);
- break;
-
- case TELQUAL_IS:
- case TELQUAL_INFO:
- /* Ignore for now. We shouldn't get it anyway. */
- break;
-
- default:
- break;
- }
- }
-
- #define OPT_REPLY_SIZE 256
- unsigned char *opt_reply;
- unsigned char *opt_replyp;
- unsigned char *opt_replyend;
-
- env_opt_start()
- {
- extern char *realloc();
- extern char *malloc();
-
- if (opt_reply)
- opt_reply = (unsigned char *)realloc(opt_reply, OPT_REPLY_SIZE);
- else
- opt_reply = (unsigned char *)malloc(OPT_REPLY_SIZE);
- if (opt_reply == NULL) {
- /*@*/ printf("env_opt_start: malloc()/realloc() failed!!!\n");
- opt_reply = opt_replyp = opt_replyend = NULL;
- return;
- }
- opt_replyp = opt_reply;
- opt_replyend = opt_reply + OPT_REPLY_SIZE;
- *opt_replyp++ = IAC;
- *opt_replyp++ = SB;
- *opt_replyp++ = TELOPT_ENVIRON;
- *opt_replyp++ = TELQUAL_IS;
- }
-
- env_opt_start_info()
- {
- env_opt_start();
- if (opt_replyp)
- opt_replyp[-1] = TELQUAL_INFO;
- }
-
- env_opt_add(ep)
- register char *ep;
- {
- register char *vp, c;
- extern char *realloc();
- extern char *env_default();
-
- if (opt_reply == NULL) /*XXX*/
- return; /*XXX*/
-
- if (ep == NULL || *ep == '\0') {
- env_default(1);
- while (ep = env_default(0))
- env_opt_add(ep);
- return;
- }
- vp = env_getvalue(ep);
- if (opt_replyp + (vp?strlen(vp):0) + strlen(ep) + 6 > opt_replyend) {
- register int len;
- opt_replyend += OPT_REPLY_SIZE;
- len = opt_replyend - opt_reply;
- opt_reply = (unsigned char *)realloc(opt_reply, len);
- if (opt_reply == NULL) {
- /*@*/ printf("env_opt_add: realloc() failed!!!\n");
- opt_reply = opt_replyp = opt_replyend = NULL;
- return;
- }
- opt_replyp = opt_reply + len - (opt_replyend - opt_replyp);
- opt_replyend = opt_reply + len;
- }
- *opt_replyp++ = ENV_VAR;
- for (;;) {
- while (c = *ep++) {
- switch(c&0xff) {
- case IAC:
- *opt_replyp++ = IAC;
- break;
- case ENV_VALUE:
- case ENV_VAR:
- case ENV_ESC:
- *opt_replyp++ = ENV_ESC;
- break;
- }
- *opt_replyp++ = c;
- }
- if (ep = vp) {
- *opt_replyp++ = ENV_VALUE;
- vp = NULL;
- } else
- break;
- }
- }
-
- env_opt_end(emptyok)
- register int emptyok;
- {
- register int len;
-
- len = opt_replyp - opt_reply + 2;
- if (emptyok || len > 6) {
- *opt_replyp++ = IAC;
- *opt_replyp++ = SE;
- if (NETROOM() > len) {
- ring_supply_data(&netoring, opt_reply, len);
- printsub('>', &opt_reply[2], len - 2);
- }
- /*@*/ else printf("slc_end_reply: not enough room\n");
- }
- if (opt_reply) {
- free(opt_reply);
- opt_reply = opt_replyp = opt_replyend = NULL;
- }
- }
-
-
-
- int
- telrcv()
- {
- register int c;
- register int scc;
- register char *sbp;
- int count;
- int returnValue = 0;
-
- scc = 0;
- count = 0;
- while (TTYROOM() > 2) {
- if (scc == 0) {
- if (count) {
- ring_consumed(&netiring, count);
- returnValue = 1;
- count = 0;
- }
- sbp = netiring.consume;
- scc = ring_full_consecutive(&netiring);
- if (scc == 0) {
- /* No more data coming in */
- break;
- }
- }
-
- c = *sbp++ & 0xff, scc--; count++;
-
- switch (telrcv_state) {
-
- case TS_CR:
- telrcv_state = TS_DATA;
- if (c == '\0') {
- break; /* Ignore \0 after CR */
- }
- else if ((c == '\n') && my_want_state_is_dont(TELOPT_ECHO) && !crmod) {
- TTYADD(c);
- break;
- }
- /* Else, fall through */
-
- case TS_DATA:
- if (c == IAC) {
- telrcv_state = TS_IAC;
- break;
- }
- /*
- * The 'crmod' hack (see following) is needed
- * since we can't * set CRMOD on output only.
- * Machines like MULTICS like to send \r without
- * \n; since we must turn off CRMOD to get proper
- * input, the mapping is done here (sigh).
- */
- if ((c == '\r') && my_want_state_is_dont(TELOPT_BINARY)) {
- if (scc > 0) {
- c = *sbp&0xff;
- if (c == 0) {
- sbp++, scc--; count++;
- /* a "true" CR */
- TTYADD('\r');
- } else if (my_want_state_is_dont(TELOPT_ECHO) &&
- (c == '\n')) {
- sbp++, scc--; count++;
- TTYADD('\n');
- } else {
- TTYADD('\r');
- if (crmod) {
- TTYADD('\n');
- }
- }
- } else {
- telrcv_state = TS_CR;
- TTYADD('\r');
- if (crmod) {
- TTYADD('\n');
- }
- }
- } else {
- TTYADD(c);
- }
- continue;
-
- case TS_IAC:
- process_iac:
- switch (c) {
-
- case WILL:
- telrcv_state = TS_WILL;
- continue;
-
- case WONT:
- telrcv_state = TS_WONT;
- continue;
-
- case DO:
- telrcv_state = TS_DO;
- continue;
-
- case DONT:
- telrcv_state = TS_DONT;
- continue;
-
- case DM:
- /*
- * We may have missed an urgent notification,
- * so make sure we flush whatever is in the
- * buffer currently.
- */
- printoption("RCVD", "IAC", DM);
- SYNCHing = 1;
- (void) ttyflush(1);
- SYNCHing = stilloob();
- settimer(gotDM);
- break;
-
- case SB:
- SB_CLEAR();
- telrcv_state = TS_SB;
- printoption("RCVD", "IAC", SB);
- continue;
-
- case IAC:
- TTYADD(IAC);
- break;
-
- case NOP:
-
- default:
- printoption("RCVD", "IAC", c);
- break;
- }
- telrcv_state = TS_DATA;
- continue;
-
- case TS_WILL:
- printoption("RCVD", "will", c);
- willoption(c);
- telrcv_state = TS_DATA;
- continue;
-
- case TS_WONT:
- printoption("RCVD", "wont", c);
- wontoption(c);
- telrcv_state = TS_DATA;
- continue;
-
- case TS_DO:
- printoption("RCVD", "do", c);
- dooption(c);
- if (c == TELOPT_NAWS) {
- sendnaws();
- } else if (c == TELOPT_LFLOW) {
- localflow = 1;
- setcommandmode();
- setconnmode(0);
- }
- telrcv_state = TS_DATA;
- continue;
-
- case TS_DONT:
- printoption("RCVD", "dont", c);
- dontoption(c);
- flushline = 1;
- setconnmode(0); /* set new tty mode (maybe) */
- telrcv_state = TS_DATA;
- continue;
-
- case TS_SB:
- if (c == IAC) {
- telrcv_state = TS_SE;
- } else {
- SB_ACCUM(c);
- }
- continue;
-
- case TS_SE:
- if (c != SE) {
- if (c != IAC) {
- /*
- * This is an error. We only expect to get
- * "IAC IAC" or "IAC SE". Several things may
- * have happend. An IAC was not doubled, the
- * IAC SE was left off, or another option got
- * inserted into the suboption are all possibilities.
- * If we assume that the IAC was not doubled,
- * and really the IAC SE was left off, we could
- * get into an infinate loop here. So, instead,
- * we terminate the suboption, and process the
- * partial suboption if we can.
- */
- SB_TERM();
- SB_ACCUM(IAC);
- SB_ACCUM(c);
- printoption("In SUBOPTION processing, RCVD", "IAC", c);
- suboption(); /* handle sub-option */
- telrcv_state = TS_IAC;
- goto process_iac;
- }
- SB_ACCUM(c);
- telrcv_state = TS_SB;
- } else {
- SB_TERM();
- SB_ACCUM(IAC);
- SB_ACCUM(SE);
- suboption(); /* handle sub-option */
- telrcv_state = TS_DATA;
- }
- }
- }
- if (count)
- ring_consumed(&netiring, count);
- return returnValue||count;
- }
-
- static int
- telsnd()
- {
- int tcc;
- int count;
- int returnValue = 0;
- char *tbp;
-
- tcc = 0;
- count = 0;
- while (NETROOM() > 2) {
- register int sc;
- register int c;
-
- if (tcc == 0) {
- if (count) {
- ring_consumed(&ttyiring, count);
- returnValue = 1;
- count = 0;
- }
- tbp = ttyiring.consume;
- tcc = ring_full_consecutive(&ttyiring);
- if (tcc == 0) {
- break;
- }
- }
- c = *tbp++ & 0xff, sc = strip(c), tcc--; count++;
- if (sc == escape) {
- /*
- * Double escape is a pass through of a single escape character.
- */
- if (tcc && strip(*tbp) == escape) {
- tbp++;
- tcc--;
- count++;
- } else {
- command(0, tbp, tcc);
- count += tcc;
- tcc = 0;
- flushline = 1;
- break;
- }
- }
- if (my_want_state_is_wont(TELOPT_BINARY)) {
- switch (c) {
- case '\n':
- /*
- * If we are in CRMOD mode (\r ==> \n)
- * on our local machine, then probably
- * a newline (unix) is CRLF (TELNET).
- */
- if (MODE_LOCAL_CHARS(globalmode)) {
- NETADD('\r');
- }
- NETADD('\n');
- flushline = 1;
- break;
- case '\r':
- if (!crlf) {
- NET2ADD('\r', '\0');
- } else {
- NET2ADD('\r', '\n');
- }
- flushline = 1;
- break;
- case IAC:
- NET2ADD(IAC, IAC);
- break;
- default:
- NETADD(c);
- break;
- }
- } else if (c == IAC) {
- NET2ADD(IAC, IAC);
- } else {
- NETADD(c);
- }
- }
- if (count)
- ring_consumed(&ttyiring, count);
- return returnValue||count; /* Non-zero if we did anything */
- }
-
- /*
- * Scheduler()
- *
- * Try to do something.
- *
- * If we do something useful, return 1; else return 0.
- *
- */
-
-
- int
- Scheduler(block)
- int block; /* should we block in the select ? */
- {
- /* One wants to be a bit careful about setting returnValue
- * to one, since a one implies we did some useful work,
- * and therefore probably won't be called to block next
- * time (TN3270 mode only).
- */
- int returnValue;
- int netin, netout, netex, ttyin, ttyout;
-
- /* Check for break signals */
-
- if (SetSignal(0L,SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_D) &
- (SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_D))
- quit();
-
- /* Decide which rings should be processed */
-
- netout = ring_full_count(&netoring) &&
- (flushline ||
- (my_want_state_is_wont(TELOPT_LINEMODE)
- ) ||
- my_want_state_is_will(TELOPT_BINARY));
- ttyout = ring_full_count(&ttyoring);
-
- ttyin = ring_empty_count(&ttyiring);
-
- netin = !ISend && ring_empty_count(&netiring);
-
- netex = !SYNCHing;
-
- /* Call to system code to process rings */
-
- returnValue = process_rings(netin, netout, netex, ttyin, ttyout, !block);
-
- /* Now, look at the input rings, looking for work to do. */
-
- if (ring_full_count(&ttyiring)) {
- returnValue |= telsnd();
- }
-
- if (ring_full_count(&netiring)) {
- returnValue |= telrcv();
- }
- return returnValue;
- }
-
- /*
- * Select from tty and network...
- */
- void
- telnet()
- {
- sys_telnet_init();
-
- if (telnetport) {
- send_do(TELOPT_SGA, 1);
- send_will(TELOPT_TTYPE, 1);
- send_will(TELOPT_NAWS, 1);
- send_will(TELOPT_TSPEED, 1);
- send_will(TELOPT_LFLOW, 1);
- send_will(TELOPT_LINEMODE, 1);
- send_do(TELOPT_STATUS, 1);
- if (env_getvalue("DISPLAY"))
- send_will(TELOPT_XDISPLOC, 1);
- send_will(TELOPT_ENVIRON, 1);
- }
-
- for (;;) {
- int schedValue;
-
- while ((schedValue = Scheduler(0)) != 0) {
- if (schedValue == -1) {
- setcommandmode();
- return;
- }
- }
-
- if (Scheduler(1) == -1) {
- setcommandmode();
- return;
- }
- }
- }
-
- /*
- * netclear()
- *
- * We are about to do a TELNET SYNCH operation. Clear
- * the path to the network.
- *
- * Things are a bit tricky since we may have sent the first
- * byte or so of a previous TELNET command into the network.
- * So, we have to scan the network buffer from the beginning
- * until we are up to where we want to be.
- *
- * A side effect of what we do, just to keep things
- * simple, is to clear the urgent data pointer. The principal
- * caller should be setting the urgent data pointer AFTER calling
- * us in any case.
- */
-
- static void
- netclear()
- {
- }
-
- /*
- * These routines add various telnet commands to the data stream.
- */
-
- static void
- doflush()
- {
- NET2ADD(IAC, DO);
- NETADD(TELOPT_TM);
- flushline = 1;
- flushout = 1;
- (void) ttyflush(1); /* Flush/drop output */
- /* do printoption AFTER flush, otherwise the output gets tossed... */
- printoption("SENT", "do", TELOPT_TM);
- }
-
- void
- xmitAO()
- {
- NET2ADD(IAC, AO);
- printoption("SENT", "IAC", AO);
- if (autoflush) {
- doflush();
- }
- }
-
-
- void
- xmitEL()
- {
- NET2ADD(IAC, EL);
- printoption("SENT", "IAC", EL);
- }
-
- void
- xmitEC()
- {
- NET2ADD(IAC, EC);
- printoption("SENT", "IAC", EC);
- }
-
-
- void
- dosynch()
- {
- netclear(); /* clear the path to the network */
- NETADD(IAC);
- setneturg();
- NETADD(DM);
- printoption("SENT", "IAC", DM);
-
- return;
- }
-
- void
- get_status()
- {
- char tmp[16];
- register char *cp;
-
- if (my_want_state_is_dont(TELOPT_STATUS)) {
- printf("Remote side does not support STATUS option\n");
- return;
- }
- if (!showoptions)
- printf("You will not see the response unless you set \"options\"\n");
-
- cp = tmp;
-
- *cp++ = IAC;
- *cp++ = SB;
- *cp++ = TELOPT_STATUS;
- *cp++ = TELQUAL_SEND;
- *cp++ = IAC;
- *cp++ = SE;
- if (NETROOM() >= cp - tmp) {
- ring_supply_data(&netoring, tmp, cp-tmp);
- printsub('>', tmp+2, cp - tmp - 2);
- }
- }
-
- void
- intp()
- {
- NET2ADD(IAC, IP);
- printoption("SENT", "IAC", IP);
- flushline = 1;
- if (autoflush) {
- doflush();
- }
- if (autosynch) {
- dosynch();
- }
- }
-
- void
- sendbrk()
- {
- NET2ADD(IAC, BREAK);
- printoption("SENT", "IAC", BREAK);
- flushline = 1;
- if (autoflush) {
- doflush();
- }
- if (autosynch) {
- dosynch();
- }
- }
-
- void
- sendabort()
- {
- NET2ADD(IAC, ABORT);
- printoption("SENT", "IAC", ABORT);
- flushline = 1;
- if (autoflush) {
- doflush();
- }
- if (autosynch) {
- dosynch();
- }
- }
-
- void
- sendsusp()
- {
- NET2ADD(IAC, SUSP);
- printoption("SENT", "IAC", SUSP);
- flushline = 1;
- if (autoflush) {
- doflush();
- }
- if (autosynch) {
- dosynch();
- }
- }
-
- void
- sendeof()
- {
- NET2ADD(IAC, xEOF);
- printoption("SENT", "IAC", xEOF);
- }
-
- void
- sendayt()
- {
- NET2ADD(IAC, AYT);
- printoption("SENT", "IAC", AYT);
- }
-
- /*
- * Send a window size update to the remote system.
- */
-
- void
- sendnaws()
- {
- long rows, cols;
- unsigned char tmp[16];
- register unsigned char *cp;
-
- if (my_state_is_wont(TELOPT_NAWS))
- return;
-
- #define PUTSHORT(cp, x) { if ((*cp++ = ((x)>>8)&0xff) == IAC) *cp++ = IAC; \
- if ((*cp++ = ((x))&0xff) == IAC) *cp++ = IAC; }
-
- if (TerminalWindowSize(&rows, &cols) == 0) { /* Failed */
- return;
- }
-
- cp = tmp;
-
- *cp++ = IAC;
- *cp++ = SB;
- *cp++ = TELOPT_NAWS;
- PUTSHORT(cp, cols);
- PUTSHORT(cp, rows);
- *cp++ = IAC;
- *cp++ = SE;
- if (NETROOM() >= cp - tmp) {
- ring_supply_data(&netoring, tmp, cp-tmp);
- printsub('>', tmp+2, cp - tmp - 2);
- }
- }
-
- tel_enter_binary(rw)
- int rw;
- {
- if (rw&1)
- send_do(TELOPT_BINARY, 1);
- if (rw&2)
- send_will(TELOPT_BINARY, 1);
- }
-
- tel_leave_binary(rw)
- int rw;
- {
- if (rw&1)
- send_dont(TELOPT_BINARY, 1);
- if (rw&2)
- send_wont(TELOPT_BINARY, 1);
- }
-